#include "game.h"

namespace gm
{
    bool running;
    bool lose;
    // 得分
    int score;
    // 行数
    int lines;
    // 等级
    int level;
    // 上一次等级
    int last_level;
    Piece* one_piece;
    Matrix playField;
    std::chrono::microseconds duration;
    Matrix frame;
    std::vector<Tetromino*> bag7;
    Tetromino holdk;
    Matrix nextPiece, resetNext;
    Matrix holdPiece, resetHold;

    void init()
    {
        running = true;
        lose = false;
        //初始化分数
        score = 0;

        playField = Matrix(10, std::vector<int>(24, 0));    // playField[x][y], x=0-9, y=0-23
        resetNext = nextPiece = Matrix(6, std::vector<int>(16, 0));
        holdPiece = resetHold = Matrix(7, std::vector<int>(4, 0));
        frame = playField;

        duration = 500ms;   // 更新延迟
        srand((unsigned)time(nullptr));

        Piece::p_playField = &playField;
        pick();
    }

    // 主逻辑
    void process()
    {
        static int cnt = 0;
        render();
        if(ut::timer(duration))
        {
            one_piece->down();
            if(one_piece->get_xy().second == one_piece->get_gy())
            {
                if(++cnt < 3) return;
                cnt = 0;

                lock();
                clear();
                pick();
                speed_up();
            }
        }
    }

    // 渲染
    void render()
    {
        frame = playField;
        nextPiece = resetNext;
        holdPiece = resetHold;

        //正常块
        auto [x, y] = one_piece->get_xy();
        for(int i=0; i < 4; i++)
        {
            auto [dx, dy] = one_piece->get_mino(i);
            frame[x+dx][y+dy] = one_piece->get_color();
        }

        //阴影块
        y = one_piece->get_gy();
        for(int i=0; i < 4; i++)
        {
            auto [dx, dy] = one_piece->get_mino(i);
            if(frame[x+dx][y+dy] == 0)
                frame[x+dx][y+dy] = 0 - one_piece->get_color();
        }

        // 下一个方块
        x = 2, y = 13;
        for(int i = 0; i < bag7.size() - 1 && y >= 0; ++i)
        {
            auto p = *bag7[i];
            nextPiece[x][y] = p[0][0].second;
            for(int j = 1; j < 4; j++)
            {
                auto [dx, dy] = p[0][j];
                nextPiece[x+dx][y+dy] = p[0][0].second;
            }
            y -= 3;
        }

        // hold
        x = 3, y = 1;
        auto p = holdk;
        if(p.size()>0)
        {
            holdPiece[x][y] = p[0][0].second;
            for(int j = 1; j < 4; j++)
            {
                auto [dx, dy] = p[0][j];
                holdPiece[x+dx][y+dy] = p[0][0].second;
            }
        }

    }

    // 生成方块
    void pick(int x ,int y)
    {
        static int cnt = 0;
        static bool visit[7];
        if(cnt == 7)
        {
            cnt = 0;
            memset(visit, 0, sizeof(visit));
        }
        while(bag7.size() < 7)
        {
            int r;
            if(cnt < 1)
            {
                r = rand() % 3;
                cnt++;
                bag7.push_back(t[r]);
                visit[r] = true;
            }
            else
            {
                r = rand() % 7;
                if(!visit[r])
                {
                    cnt++;
                    bag7.push_back(t[r]);
                    visit[r] = true;
                }
            }
        }
        if(one_piece != nullptr) 
            delete one_piece;
        one_piece = new Piece(*bag7[0], x, y, 0);
        bag7.erase(bag7.begin());
    }

    // 锁定
    void lock()
    {
        render();
        playField = frame;
        if(one_piece->get_xy().second >= 20)
        {
            lose = true;
        }
        else
        {
            //锁定加25分
            score += 25;
        }
    }

    // 消行
    void clear()
    {
        std::vector<int> line_y;
        bool is_check[22] = {false};
        auto y = one_piece->get_xy().second;
        for(int i = 0; i < 4; i++)
        {
            auto dy = one_piece->get_mino(i).second;
            if(is_check[y + dy]) continue;

            is_check[y + dy] = true;
            bool is_line = true;
            for(int x = 0; x < 10; x++)
                is_line &= playField[x][y + dy] != 0;
            
            if(is_line)
                line_y.push_back(y + dy);
        }
        
        sort(line_y.begin(), line_y.end(), std::greater<int>());
        if(!line_y.empty())
            for(auto y : line_y)
                for(int x = 0; x < 10; x++)
                    for(int py = y; py < 21; py++)
                        playField[x][py] = playField[x][py + 1];
        //更新消行数
        lines += line_y.size();
        //更新等级
        level = (lines / 10) + 1;
        //消行加分
        if(line_y.size() > 0)
        score += 100 * (1 << (line_y.size() - 1))* level;
        line_y.clear(); // 清空消行行数
    }

    // 加速
    void speed_up()
    {
        if(last_level < level)
            duration = duration / 10 * 9;
        last_level = level;
    }

    void quit()
    {
        running = false;
    }

    void rotate()
    {
        one_piece->rotate();
    }

    void left()
    {
        one_piece->left();
    }

    void right()
    {
        one_piece->right();
    }

    void down()
    {
        one_piece->down();
    }

    // 直降
    void drop()
    {
        auto [x, y] = one_piece->get_xy();
        int gy = one_piece->get_gy();
        int dy = y;
        one_piece->down(y - gy);
    }

    void hold()
    { 
        static bool k = true;
        if(one_piece->get_xy().second == one_piece->get_gy())
            return ;
        auto [x,y]=one_piece->get_xy();
        if(k)
        {
            holdk = one_piece->get_tetro();
            pick(x,y);
            k = false;
        }
        else
        {
            auto temp = one_piece->get_tetro();
            one_piece->change_tetro(holdk);
            if(one_piece->test(x,y))
                holdk = temp;
            else
                one_piece->change_tetro(temp);
        }    
    }  

    void help()
    {
        dw::help();
    }
} // namespace
